package com.atguigu.lease.web.api.service.impl;

import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.atguigu.lease.common.exception.StgyException;
import com.atguigu.lease.common.result.ResultCodeEnum;
import com.atguigu.lease.common.util.HttpUtils;
import com.atguigu.lease.common.util.JwtUtil;
import com.atguigu.lease.model.entity.UserInfo;
import com.atguigu.lease.web.api.dto.UserLoginDto;
import com.atguigu.lease.web.api.service.LoginService;
import com.atguigu.lease.web.api.service.UserInfoService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements LoginService {
    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Resource
    UserInfoService userInfoService;
    @Override
    public boolean sendCode(String phone) {
        //1、校验手机号码格式
        if(!PhoneUtil.isMobile(phone)){
            throw new StgyException(ResultCodeEnum.DATA_ERROR);
        }
        //2、校验手机号获取验证码的频率
        //  1分钟内只能发送一次
        //setnx: 设置一个过期时间为1分钟的key  如果设置成功可以继续执行
        String perMinKey = "stgy:app:per:min:"+phone;
        Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(perMinKey, "1", 1, TimeUnit.MINUTES);
        if(!flag){
            throw new StgyException(ResultCodeEnum.APP_SEND_SMS_TOO_OFTEN);
        }
        //  1天内只能发送3次
        String perDayKey = "stgy:app:per:day:"+phone;
        String countStr = stringRedisTemplate.opsForValue().get(perDayKey);
        if(!StringUtils.isEmpty(countStr) && Integer.parseInt(countStr) >=3 ){
            throw new StgyException(ResultCodeEnum.APP_SEND_SMS_TOO_MANY);
        }

        //3、发送短信
        sendMsg(phone);
        //4、更新发送验证码的次数
        Long count = stringRedisTemplate.opsForValue().increment(perDayKey);
        if(count==1l){
            //表示第一次发送短信
            stringRedisTemplate.expire(perDayKey,1,TimeUnit.DAYS);
        }
        return true;
    }
    //登录业务
    @Override
    public String login(UserLoginDto loginDto) {
        //1、参数校验：
        String phone = loginDto.getPhone();
        String code = loginDto.getCode();
        if(!PhoneUtil.isMobile(phone) ||
            StringUtils.isEmpty(code)){
            throw new StgyException(ResultCodeEnum.DATA_ERROR);
        }
        //2、验证码校验：
        //根据手机号拼接key获取redis缓存的验证码
        String codeKey = "stgy:app:code:"+ phone;
        String cachedCode = stringRedisTemplate.opsForValue().get(codeKey);
        if(!code.equals(cachedCode)){
            throw new StgyException(ResultCodeEnum.APP_LOGIN_CODE_ERROR);
        }
        //3、根据手机号查询用户信息
        UserInfo userInfo = userInfoService.getOne(Wrappers.lambdaQuery(UserInfo.class)
                .eq(UserInfo::getPhone, phone)
                .last("limit 1"));
        // 虽然 web-api和admin 都需要操作相同的表 都需要创建相同的mapper和service，但是他们的业务方法不一样 controlle让接口不一样 配置组件类不一样
        //     springboot web项目不会互相引入依赖
        //  3.1 如果查询失败 将用户保存到数据库中  新用户注册
        if(userInfo==null){
            userInfo = new UserInfo();
            userInfo.setPhone(phone);
            userInfo.setNickname("谷粉_"+ UUID.randomUUID().toString().substring(0,8));
            userInfo.setAvatarUrl("https://img.bosszhipin.com/boss/avatar/avatar_16.png");
            userInfo.setStatus(1);
            userInfoService.save(userInfo);
        }
        //  3.2 查询成功  老用户登录

        //4、将上面的用户信息创建为jwt的token返回
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        String token = JwtUtil.createToken(userInfo,requestAttributes.getRequest());
        //5、删除验证码缓存
        stringRedisTemplate.delete(codeKey);
        return token;
    }

    private boolean sendMsg(String phone) {
        // 使用了HttpClient 发送http协议的请求
        //java代码要访问的发送短信的服务 接口
        String host = "https://cxkjsms.market.alicloudapi.com";
        String path = "/chuangxinsms/dxjk";
        String method = "POST";
        String appcode = "8e45699f00ff4bdbb807664045acd813";//开通服务后 买家中心-查看AppCode
        Map<String, String> headers = new HashMap<String, String>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + appcode);
        Map<String, String> querys = new HashMap<String, String>();
        String code = RandomUtil.randomNumbers(6);
        querys.put("content", "【尚硅谷】你的验证码是："+code+"，"+20+"分钟内有效！");
        querys.put("mobile", phone);
        Map<String, String> bodys = new HashMap<String, String>();
        try {
            //向第三方平台发送短信的业务代码：可以注释掉
//            //根据上面的配置发送网络请求 得到的结果解析为响应对象
//            HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
//            System.out.println(response.toString());
//            //判断响应报文状态码：200表示成功
//            if(200 != response.getStatusLine().getStatusCode()){
//                throw new RuntimeException("短信发送失败");
//            }
//            //获取报文的响应体内容
//            String json = EntityUtils.toString(response.getEntity());
//            Map<String,Object> map = JSON.parseObject(json, Map.class);
//            System.out.println("map = " + map);
//            if(!"Success".equalsIgnoreCase(map.get("ReturnStatus").toString())){
//                throw new RuntimeException("短信发送失败");
//            }

            stringRedisTemplate.opsForValue().set( "stgy:app:code:"+ phone, code ,20, TimeUnit.MINUTES );
            //获取response的body
            //System.out.println(EntityUtils.toString(response.getEntity()));
            return true;
        } catch (Exception e) {
//            e.printStackTrace();
//            return false;
            throw new StgyException(ResultCodeEnum.MEG_SEND_ERROR);
        }
    }

}
